using Abp;
using Abp.AspNetCore.Configuration;
using Abp.AspNetCore.Mvc.Extensions;
using Abp.AspNetCore.Mvc.Results;
using Abp.Authorization;
using Abp.Collections.Extensions;
using Abp.Dependency;
using Abp.Domain.Entities;
using Abp.Events.Bus;
using Abp.Events.Bus.Exceptions;
using Abp.Logging;
using Abp.Runtime.Validation;
using Abp.UI;
using Abp.Web.Models;
using AutoMapper.Internal;
using Castle.Core.Logging;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;

namespace Yozeev.Common
{
    /// <summary>
    /// 
    /// </summary>
    public class ExceptionFilter : IExceptionFilter, ITransientDependency
    {
        /// <summary>
        /// 
        /// </summary>
        public ILogger Logger { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public IEventBus EventBus { get; set; }

        private readonly IErrorInfoBuilder _errorInfoBuilder;
        private readonly IAbpAspNetCoreConfiguration _configuration;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="errorInfoBuilder"></param>
        /// <param name="configuration"></param>
        public ExceptionFilter(IErrorInfoBuilder errorInfoBuilder, IAbpAspNetCoreConfiguration configuration)
        {
            _errorInfoBuilder = errorInfoBuilder;
            _configuration = configuration;

            Logger = NullLogger.Instance;
            EventBus = NullEventBus.Instance;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        public void OnException(ExceptionContext context)
        {
            if (!context.ActionDescriptor.IsControllerAction())
            {
                return;
            }
            var list = DataException.getList();
            if (context.Exception.InnerException != null)
            {
                Logger.Error("InnerException", context.Exception.InnerException);
                var exception = list.Where(m => context.Exception.InnerException.Message.Contains(m.code)).FirstOrDefault();
                if (exception != null)
                {
                    throw new AbpException(exception.name);
                }
            }
            Logger.Error("Exception", context.Exception);
            throw new AbpException(context.Exception.Message);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        private void HandleAndWrapException(ExceptionContext context)
        {
            if (!ActionResultHelper.IsObjectResult(context.ActionDescriptor.GetMethodInfo().ReturnType))
            {
                return;
            }

            context.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
            var errorInfo = _errorInfoBuilder.BuildForException(context.Exception);
            errorInfo.Code = GetStatusCode(context, errorInfo);
            context.Result = new ObjectResult(
                new AjaxResponse(
                    errorInfo,
                    context.Exception is AbpAuthorizationException
                )
            );

            EventBus.Trigger(this, new AbpHandledExceptionData(context.Exception));

            context.Exception = null; //Handled!
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <param name="errorInfo"></param>
        /// <returns></returns>
        protected virtual int GetStatusCode(ExceptionContext context, ErrorInfo errorInfo)
        {
            if (context.Exception is AbpAuthorizationException)
            {
                return context.HttpContext.User.Identity.IsAuthenticated
                    ? (int)HttpStatusCode.Forbidden
                    : (int)HttpStatusCode.Unauthorized;
            }

            if (context.Exception is AbpValidationException)
            {
                return (int)HttpStatusCode.BadRequest;
            }

            if (context.Exception is EntityNotFoundException)
            {
                return (int)HttpStatusCode.NotFound;
            }

            if (context.Exception is UserFriendlyException)
            {
                return errorInfo.Code;
            }

            return (int)HttpStatusCode.InternalServerError;
        }
    }
}
